/*
 * Licensed to the Apache Software Foundation (ASF) under one or more
 * contributor license agreements.  See the NOTICE file distributed with
 * this work for additional information regarding copyright ownership.
 * The ASF licenses this file to You under the Apache License, Version 2.0
 * (the "License"); you may not use this file except in compliance with
 * the License.  You may obtain a copy of the License at
 *
 *      http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */
/*
 * JTAUtils.java
 *
 * Created on April 12, 2005, 11:45 AM
 */

package org.apache.geode.internal.jta;

/**
 *
 */

//import java.io.*;
import java.util.*;
//import java.net.*;
import org.apache.geode.cache.*;
//import org.apache.geode.distributed.*;
//import org.apache.geode.util.concurrent.locks.*;
//import java.util.Hashtable;
//import javax.naming.InitialContext;
import javax.naming.Context;
import java.sql.*;
import javax.sql.*;
//import javax.transaction.*;
//import java.lang.Exception.*;
//import java.lang.RuntimeException;
//import java.sql.SQLException.*;
import javax.naming.NamingException;
//import javax.naming.NoInitialContextException;
//import javax.transaction.SystemException;
//import org.apache.geode.internal.jta.CacheUtils;

public class JTAUtils {
    

    public  Region currRegion;
    public  Cache cache;
     /** This is used to store each Regions original attributes for reset purposes */
    private HashMap regionDefaultAttrMap = new HashMap();

    public JTAUtils(Cache cache,Region region){
	this.cache=cache;
	this.currRegion= region;
    }

    public static long start () {
        long beginTime = getCurrentTimeMillis ();
        return beginTime;
    }

    public static long stop () {
       long endTime = getCurrentTimeMillis ();
       return endTime;
    }

    public static long elapsedTime (long endTime, long beginTime) {
       return endTime - beginTime;
    }

    static long getCurrentTimeMillis () {
      return System.currentTimeMillis ();
    }

     /**
   * Calls the corresponding cache APIs to
   * create a sub-region by name 'command'
   * in the current region.
   */
   public void mkrgn(String command) throws Exception {

      try {
          String name = command;
          AttributesFactory fac = new AttributesFactory(this.currRegion.getAttributes());
          Region nr = this.currRegion.createSubregion(name,fac.create());
          regionDefaultAttrMap.put
          (nr.getFullPath(), fac.create());
      }
      catch (Exception e) {
          //fail (" unable to make region..." + e.getMessage ());
          throw new Exception (" failed in mkrgn " + command);
      }

   }

    /**
   * Checks whether a region passed in the param exists in the
   * curr region or not. If doesnt exist then calls mkrgn() to create it.
   * Finally makes data member currRegion point to that region.
   */
   public void getRegionFromCache (String region) throws Exception {
      try {
          Region subr  = this.currRegion.getSubregion(region);

          if(subr == null)
          {
              mkrgn (region);
              currRegion = this.currRegion.getSubregion(region);
          }
          else
          {
              currRegion = subr;
          }

      }
      catch (Exception e) {
          //fail (" unable to get sub-region...");
          System.out.println ("err: " + e);
          e.printStackTrace ();
          throw new Exception (" failed in getRegionFromCache ");
      }

  }

   /**
   * Parses a <code>command</code> and places each of its tokens in a
   * <code>List</code>.
   */
  public boolean parseCommand(String command, List list) {
//    String strTemp = command;
    boolean done = false;
    boolean success = false;
    int space = -1;
    do {
      space = command.indexOf(' ');
      if (space < 0) {
        done= true;
        list.add(command);
        break;
      }
      String str = command.substring(0,space);
      list.add(str);
      command = command.substring(space+1, command.length());
      success = true;
    } while(!done);
    return success;
  }

  /**
   * Gets the value of the key entry into the current region.
   * Returns the value and prints the pair with help of printEntry() to stdout
   * @see Region#put
   * Modified to return string value
   */

  public String get(String command) throws CacheException {
    String value = null;

//       try {
          String name = command;
          Object valueBytes = this.currRegion.get(name);
          value = printEntry(name, valueBytes);
//       }
//       catch (CacheException e) {
//           //fail (" unable to get value..." + e.getMessage ());
//           throw new CacheExistsException("failed getting region: " + command);
//       }
    return value;
  }

   /**
   * Puts an entry into the current region
   *
   * @see Region#put
   */
  public void put(String command, String val) throws Exception {
    try {
            LinkedList list = new LinkedList();
            // syntax of put from CacheRunner cli help-- prabir
            command = "put " + command +  " " + val;
            parseCommand(command, list);
            if (list.size() < 3 ) {
              System.out.println("Error:put requires a name and a value");
            }
            else {
              String name = (String) list.get(1);
              String value = (String) list.get(2);
              if (list.size() > 3) {
                String objectType = (String) list.get(3);
                if (objectType.equalsIgnoreCase("int")) {
                  this.currRegion.put(name,Integer.valueOf(value));
                }
                else if (objectType.equalsIgnoreCase("str")) {
                  this.currRegion.put(name,value);
                }
                else {
                  System.out.println("Invalid object type specified. Please see help.");
                  //fail (" Invalid object type specified !!");
                }
              }
              else {
                this.currRegion.put(name,value.getBytes());
              }
            }
    }
    catch (Exception e) {
        //fail (" unable to put..." + e.getMessage ());
        throw new Exception ("unable to put: " + e);
    }

  }

   /**
   * Prints the key/value pair for an entry to stdout
   * This method recognizes a subset of all possible object types.
   * Modified to return the value string
   */
  public String printEntry(String key, Object valueBytes) {
    String value = null;

    if (valueBytes != null) {
      if (valueBytes instanceof byte[]) {
        value = new String("byte[]: \"" + new String((byte[]) valueBytes) + "\"");
      }
      else if (valueBytes instanceof String) {
        value = new String("String: \"" + valueBytes + "\"");
      }
      else if (valueBytes instanceof Integer) {
        value = new String("Integer: \"" + valueBytes.toString() + "\"");
      }
    else {
      value = new String ("No value in cache.");
    }

    System.out.print ("     " + key + " -> " + value);
  }
    return value;
  }

   /**
   * Returns a constant width space to stdout
   * This method is used to print test pass/fail msg
   * after a constant width from the test execution stage
   */

  public static String repeatChar (char character, int repeatCount) {

    StringBuffer stringBuffer = new StringBuffer(repeatCount);
    for (int i = 1; i <= repeatCount; i++) {
        stringBuffer.append(character);
    }
    return stringBuffer.toString();
  }

   /**
   * This method is used to parse the string with
   * delimeter ':'returned by get().
   * The delimeter is appended by printEntry().
   */
  public String parseGetValue (String str) {

      String returnVal = null;
      if (str == null) {
//          returnVal = str;  (redundant assignment)
      }
      if (str.indexOf(':') != -1)
      {
          String tokens[] = str.split(":");
          returnVal = tokens[1].trim();
      }
      else if (str.equals("No value in cache.")) { // dont change this string!!
          returnVal = str;
      }
      return returnVal;
  }


   /**
   * This method is used to delete all rows from the timestamped
   * table created by createTable() in CacheUtils class.
   */
  public int deleteRows (String tableName) throws NamingException, SQLException {

      Context ctx = cache.getJNDIContext();
      DataSource da = (DataSource)ctx.lookup("java:/SimpleDataSource"); // doesn't req txn

      Connection conn = da.getConnection();
      Statement stmt = conn.createStatement();
      int rowsDeleted = 0;  // assume that rows are always inserted in CacheUtils
      String sql =  "";
      sql = "select * from " + tableName;
      ResultSet rs = stmt.executeQuery(sql);
      if (rs.next()) {

         sql = "delete from  "+tableName;
         rowsDeleted = stmt.executeUpdate(sql);
      }

      rs.close();

      stmt.close();
      conn.close ();

   return rowsDeleted;
 }


  /**
   * This method is used to return number rows from the timestamped
   * table created by createTable() in CacheUtils class.
   */
 public int  getRows (String tableName) throws NamingException, SQLException {

    Context ctx = cache.getJNDIContext();
    DataSource ds = (DataSource) ctx.lookup("java:/SimpleDataSource");

    String sql = "select * from "+tableName;

    Connection conn = ds.getConnection();
        Statement sm = conn.createStatement();
        ResultSet rs = sm.executeQuery(sql);
        int counter = 0;
        while(rs.next())
        {
            counter++;
            //System.out.println("id "+rs.getString(1)+ " name "+rs.getString(2));
        }
        rs.close();
        conn.close();

     return counter;
 }

 
  /**
   * This method is used to search for pattern which is the PK
   * in the timestamped table
   * created by createTable() in CacheUtils class.
   */
 public boolean checkTableAgainstData (String tableName, String pattern) throws NamingException, SQLException {
     Context ctx = cache.getJNDIContext();
     DataSource ds = (DataSource) ctx.lookup("java:/SimpleDataSource");
     boolean found = false;
     String id_str = "";

     String sql = "select * from "+tableName;

     Connection conn = ds.getConnection();
        Statement sm = conn.createStatement();
        ResultSet rs = sm.executeQuery(sql);
        while(rs.next())
        {
            System.out.println ("id:" + rs.getString (1));
            System.out.println ("name:" + rs.getString (2));
            id_str = rs.getString(1);
            if (id_str.equals(pattern)) {
                found = true;
                break;
            }
            else
                continue;
        }
        rs.close();
        conn.close();
     return found;
 }

 
} // end of class











